#pragma once
#ifndef _GEOMETRY_2D_VECTOR_
#define _GEOMETRY_2D_VECTOR_

//================================================================================================================================
//================================================================================================================================
// Локальные
#include "math/math.h"
#include "geometry/2d/point.h"
#include "core_global.h"

//================================================================================================================================
//================================================================================================================================
namespace geometry
{
    namespace _2d
    {
        //! Вектор в двумерном пространстве
        class CORE_EXPORT Vector
        {
        public:
            //! Создание нулевого вектора (вектора (0;0)).
            Vector() : m_x(0.), m_y(0.) {}

            //! Создание вектора с указанными компонентами.
            Vector(double x, double y) : m_x(x), m_y(y) {}

            //! Создать вектор с началом в точке \e A и концом в точке \e B.
            Vector(Point A, Point B) : m_x(B.x() - A.x()), m_y(B.y() - A.y()){}

            //! Получить первую компоненту вектора.
            double x() const {return m_x;}

            //! Получить вторую компоненту вектора.
            double y() const {return m_y;}

            //! Изменить первую компоненту вектора.
            void setX(double x) {m_x = x;}

            //! Изменить вторую компоненту вектора.
            void setY(double y) {m_y = y;}

            //! Длина вектора.
            double length() const {return qSqrt(m_x*m_x + m_y*m_y);}

            //! Приведение вектора к единичной длине.
            void normalize(){double h = length(); m_x /= h; m_y /= h;}

            //! Получение вектора нормального данному.
            //
            //! Для получения нормального вектора используется следующий алгоритм: нормальным к ветору (x,y) будет вектор (y, -x).
            static Vector normal(const Vector &vector){return Vector(vector.m_y, -vector.m_x);}

            //! Прибавление к данному ветору вектора \e vector.
            Vector &operator+=(const Vector &vector){m_x += vector.m_x; m_y += vector.m_y; return *this;}

            //! Вычитание из данного ветора вектора \e vector.
            Vector &operator-=(const Vector &vector){m_x -= vector.m_x; m_y -= vector.m_y; return *this;}

            //! Умножение данного вектора на скаляр \e factor.
            Vector &operator*=(double factor){m_x *= factor; m_y *= factor; return *this;}

            //! Деление данного вектора на скаляр \e divisor.
            Vector &operator/=(double divisor){m_x /= divisor; m_y /= divisor; return *this;}

            //! Скалярное произведение векторов.
            static double dotProduct(const Vector& v1, const Vector& v2){return v1.m_x*v2.m_x + v1.m_y*v2.m_y;}

        private:
            double m_x;	//!< Первая компонента вектора.
            double m_y;	//!< Вторая компонента вектора.
        };

        //========================================================================================================================
        //========================================================================================================================
        //! Сравнение векторов.
        //! \relates Vector
        //! \remarks При проверке координат вектора на равенство, разность соответствующих компонент сравнивется с константой
        //! \e DBL_EPSILON, определённой в файле <float.h>. \e DBL_EPSILON - это минимальное значение, которое при прибавлении
        //! его к единице, меняет ее значение.
        inline bool operator==(const Vector &v1, const Vector &v2){
            return qAbs(v1.x() - v2.x()) < DBL_EPSILON && qAbs(v1.y() - v2.y()) < DBL_EPSILON;
        }

        //! Сравнение векторов.
        //! \relates Vector
        //! \remarks При проверке координат вектора на равенство, разность соответствующих компонент сравнивется с константой
        //! \e DBL_EPSILON, определённой в файле <float.h>. \e DBL_EPSILON - это минимальное значение, которое при прибавлении
        //! его к единице, меняет ее значение.
        inline bool operator!=(const Vector &v1, const Vector &v2){
            return qAbs(v1.x() - v2.x()) > DBL_EPSILON || qAbs(v1.y() - v2.y()) > DBL_EPSILON;
        }

        //! Сложение векторов.
        //! \relates Vector
        inline const Vector operator+(const Vector &v1, const Vector &v2){
            return Vector(v1.x() + v2.x(), v1.y() + v2.y());
        }

        //! Вычитание векторов.
        //! \relates Vector
        inline const Vector operator-(const Vector &v1, const Vector &v2){
            return Vector(v1.x() - v2.x(), v1.y() - v2.y());
        }

        //! Умножение вектора на скаляр.
        //! \relates Vector
        inline const Vector operator*(double factor, const Vector &vector){
            return Vector(vector.x()*factor, vector.y()*factor);
        }

        //! Умножение вектора на скаляр.
        //! \relates Vector
        inline const Vector operator*(const Vector &vector, double factor){
            return Vector(vector.x()*factor, vector.y()*factor);
        }

        //! Деление вектора на скаляр.
        //! \relates Vector
        inline const Vector operator/(const Vector &vector, double divisor){
            return Vector(vector.x()/divisor, vector.y()/divisor);
        }

        //! Получение вектора, обратного (по направлению) данному.
        //! \relates Vector
        inline const Vector operator-(const Vector &vector){
            return Vector(-vector.x(), -vector.y());
        }

        //========================================================================================================================
        //========================================================================================================================
        //! Вывод вектора в текстовый поток.
        //! \relates Vector
        inline QTextStream& operator<<(QTextStream& stream, const Vector &vector)
        {
            stream << vector.x() << " " << vector.y();
            return stream;
        }

        //! Ввод вектора из текстового потока.
        //! \relates Vector
        inline QTextStream& operator>>(QTextStream& stream, Vector &vector)
        {
            double x, y;
            stream >> x >> y;
            vector.setX(x);
            vector.setY(y);
            return stream;
        }
    }
}

#endif // _GEOMETRY_2D_VECTOR_
